1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package sun.java2d;
27
28 import java.awt.Graphics;
29 import java.awt.Graphics2D;
30 import java.awt.RenderingHints;
31 import java.awt.RenderingHints.Key;
32 import java.awt.geom.Area;
33 import java.awt.geom.AffineTransform;
34 import java.awt.geom.NoninvertibleTransformException;
35 import java.awt.AlphaComposite;
36 import java.awt.BasicStroke;
37 import java.awt.image.BufferedImage;
38 import java.awt.image.BufferedImageOp;
39 import java.awt.image.RenderedImage;
40 import java.awt.image.renderable.RenderableImage;
41 import java.awt.image.renderable.RenderContext;
42 import java.awt.image.AffineTransformOp;
43 import java.awt.image.Raster;
44 import java.awt.image.WritableRaster;
45 import java.awt.Image;
46 import java.awt.Composite;
47 import java.awt.Color;
48 import java.awt.image.ColorModel;
49 import java.awt.GraphicsConfiguration;
50 import java.awt.Paint;
51 import java.awt.GradientPaint;
52 import java.awt.LinearGradientPaint;
53 import java.awt.RadialGradientPaint;
54 import java.awt.TexturePaint;
55 import java.awt.geom.Rectangle2D;
56 import java.awt.geom.PathIterator;
57 import java.awt.geom.GeneralPath;
58 import java.awt.Shape;
59 import java.awt.Stroke;
60 import java.awt.FontMetrics;
61 import java.awt.Rectangle;
62 import java.text.AttributedCharacterIterator;
63 import java.awt.Font;
64 import java.awt.image.ImageObserver;
65 import java.awt.Transparency;
66 import java.awt.font.GlyphVector;
67 import java.awt.font.TextLayout;
68 import sun.font.FontDesignMetrics;
69 import sun.font.FontUtilities;
70 import sun.java2d.pipe.PixelDrawPipe;
71 import sun.java2d.pipe.PixelFillPipe;
72 import sun.java2d.pipe.ShapeDrawPipe;
73 import sun.java2d.pipe.ValidatePipe;
74 import sun.java2d.pipe.ShapeSpanIterator;
75 import sun.java2d.pipe.Region;
76 import sun.java2d.pipe.TextPipe;
77 import sun.java2d.pipe.DrawImagePipe;
78 import sun.java2d.pipe.LoopPipe;
79 import sun.java2d.loops.FontInfo;
80 import sun.java2d.loops.RenderLoops;
81 import sun.java2d.loops.CompositeType;
82 import sun.java2d.loops.SurfaceType;
83 import sun.java2d.loops.Blit;
84 import sun.java2d.loops.MaskFill;
85 import sun.font.FontManager;
86 import java.awt.font.FontRenderContext;
87 import sun.java2d.loops.XORComposite;
88 import sun.awt.ConstrainableGraphics;
89 import sun.awt.SunHints;
90 import java.util.Map;
91 import java.util.Iterator;
92 import sun.java2d.DestSurfaceProvider;
93 import sun.misc.PerformanceLogger;
94
95
96
97
98
99
100
101
102
103
104 public final class SunGraphics2D
105 extends Graphics2D
106 implements ConstrainableGraphics, Cloneable, DestSurfaceProvider
107 {
108
109
110
111
112 public static final int PAINT_CUSTOM = 6;
113 public static final int PAINT_TEXTURE = 5;
114 public static final int PAINT_RAD_GRADIENT = 4;
115 public static final int PAINT_LIN_GRADIENT = 3;
116 public static final int PAINT_GRADIENT = 2;
117 public static final int PAINT_ALPHACOLOR = 1;
118 public static final int PAINT_OPAQUECOLOR = 0;
119
120
121 public static final int COMP_CUSTOM = 3;
122 public static final int COMP_XOR = 2;
123 public static final int COMP_ALPHA = 1;
124 public static final int COMP_ISCOPY = 0;
125
126
127
128
129
130
131 public static final int STROKE_CUSTOM = 3;
132 public static final int STROKE_WIDE = 2;
133 public static final int STROKE_THINDASHED = 1;
134 public static final int STROKE_THIN = 0;
135
136
137 public static final int TRANSFORM_GENERIC = 4;
138 public static final int TRANSFORM_TRANSLATESCALE = 3;
139 public static final int TRANSFORM_ANY_TRANSLATE = 2;
140 public static final int TRANSFORM_INT_TRANSLATE = 1;
141 public static final int TRANSFORM_ISIDENT = 0;
142
143
144 public static final int CLIP_SHAPE = 2;
145 public static final int CLIP_RECTANGULAR = 1;
146 public static final int CLIP_DEVICE = 0;
147
148
149 public int eargb;
150 public int pixel;
151
152 public SurfaceData surfaceData;
153
154 public PixelDrawPipe drawpipe;
155 public PixelFillPipe fillpipe;
156 public DrawImagePipe imagepipe;
157 public ShapeDrawPipe shapepipe;
158 public TextPipe textpipe;
159 public MaskFill alphafill;
160
161 public RenderLoops loops;
162
163 public CompositeType imageComp;
164
165 public int paintState;
166 public int compositeState;
167 public int strokeState;
168 public int transformState;
169 public int clipState;
170
171 public Color foregroundColor;
172 public Color backgroundColor;
173
174 public AffineTransform transform;
175 public int transX;
176 public int transY;
177
178 protected static final Stroke defaultStroke = new BasicStroke();
179 protected static final Composite defaultComposite = AlphaComposite.SrcOver;
180 private static final Font defaultFont =
181 new Font(Font.DIALOG, Font.PLAIN, 12);
182
183 public Paint paint;
184 public Stroke stroke;
185 public Composite composite;
186 protected Font font;
187 protected FontMetrics fontMetrics;
188
189 public int renderHint;
190 public int antialiasHint;
191 public int textAntialiasHint;
192 private int fractionalMetricsHint;
193
194
195 public int lcdTextContrast;
196 private static int lcdTextContrastDefaultValue = 140;
197
198 private int interpolationHint;
199 public int strokeHint;
200
201 public int interpolationType;
202
203
204 public RenderingHints hints;
205
206 public Region constrainClip;
207 public int constrainX;
208 public int constrainY;
209
210 public Region clipRegion;
211 public Shape usrClip;
212 protected Region devClip;
213
214
215 private boolean validFontInfo;
216 private FontInfo fontInfo;
217 private FontInfo glyphVectorFontInfo;
218 private FontRenderContext glyphVectorFRC;
219
220 private final static int slowTextTransformMask =
221 AffineTransform.TYPE_GENERAL_TRANSFORM
222 | AffineTransform.TYPE_MASK_ROTATION
223 | AffineTransform.TYPE_FLIP;
224
225 static {
226 if (PerformanceLogger.loggingEnabled()) {
227 PerformanceLogger.setTime("SunGraphics2D static initialization");
228 }
229 }
230
231 public SunGraphics2D(SurfaceData sd, Color fg, Color bg, Font f) {
232 surfaceData = sd;
233 foregroundColor = fg;
234 backgroundColor = bg;
235
236 transform = new AffineTransform();
237 stroke = defaultStroke;
238 composite = defaultComposite;
239 paint = foregroundColor;
240
241 imageComp = CompositeType.SrcOverNoEa;
242
243 renderHint = SunHints.INTVAL_RENDER_DEFAULT;
244 antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
245 textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
246 fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
247 lcdTextContrast = lcdTextContrastDefaultValue;
248 interpolationHint = -1;
249 strokeHint = SunHints.INTVAL_STROKE_DEFAULT;
250
251 interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
252
253 validateColor();
254
255 font = f;
256 if (font == null) {
257 font = defaultFont;
258 }
259
260 setDevClip(sd.getBounds());
261 invalidatePipe();
262 }
263
264 protected Object clone() {
265 try {
266 SunGraphics2D g = (SunGraphics2D) super.clone();
267 g.transform = new AffineTransform(this.transform);
268 if (hints != null) {
269 g.hints = (RenderingHints) this.hints.clone();
270 }
271
272
273
274
275
276
277 if (this.fontInfo != null) {
278 if (this.validFontInfo) {
279 g.fontInfo = (FontInfo)this.fontInfo.clone();
280 } else {
281 g.fontInfo = null;
282 }
283 }
284 if (this.glyphVectorFontInfo != null) {
285 g.glyphVectorFontInfo =
286 (FontInfo)this.glyphVectorFontInfo.clone();
287 g.glyphVectorFRC = this.glyphVectorFRC;
288 }
289
290 return g;
291 } catch (CloneNotSupportedException e) {
292 }
293 return null;
294 }
295
296
297
298
299 public Graphics create() {
300 return (Graphics) clone();
301 }
302
303 public void setDevClip(int x, int y, int w, int h) {
304 Region c = constrainClip;
305 if (c == null) {
306 devClip = Region.getInstanceXYWH(x, y, w, h);
307 } else {
308 devClip = c.getIntersectionXYWH(x, y, w, h);
309 }
310 validateCompClip();
311 }
312
313 public void setDevClip(Rectangle r) {
314 setDevClip(r.x, r.y, r.width, r.height);
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328
329 public void constrain(int x, int y, int w, int h) {
330 if ((x|y) != 0) {
331 translate(x, y);
332 }
333 if (transformState >= TRANSFORM_TRANSLATESCALE) {
334 clipRect(0, 0, w, h);
335 return;
336 }
337 x = constrainX = transX;
338 y = constrainY = transY;
339 w = Region.dimAdd(x, w);
340 h = Region.dimAdd(y, h);
341 Region c = constrainClip;
342 if (c == null) {
343 c = Region.getInstanceXYXY(x, y, w, h);
344 } else {
345 c = c.getIntersectionXYXY(x, y, w, h);
346 if (c == constrainClip) {
347
348 return;
349 }
350 }
351 constrainClip = c;
352 if (!devClip.isInsideQuickCheck(c)) {
353 devClip = devClip.getIntersection(c);
354 validateCompClip();
355 }
356 }
357
358 protected static ValidatePipe invalidpipe = new ValidatePipe();
359
360
361
362
363 protected void invalidatePipe() {
364 drawpipe = invalidpipe;
365 fillpipe = invalidpipe;
366 shapepipe = invalidpipe;
367 textpipe = invalidpipe;
368 imagepipe = invalidpipe;
369 loops = null;
370 }
371
372 public void validatePipe() {
373 surfaceData.validatePipe(this);
374 }
375
376
377
378
379
380
381
382
383 Shape intersectShapes(Shape s1, Shape s2, boolean keep1, boolean keep2) {
384 if (s1 instanceof Rectangle && s2 instanceof Rectangle) {
385 return ((Rectangle) s1).intersection((Rectangle) s2);
386 }
387 if (s1 instanceof Rectangle2D) {
388 return intersectRectShape((Rectangle2D) s1, s2, keep1, keep2);
389 } else if (s2 instanceof Rectangle2D) {
390 return intersectRectShape((Rectangle2D) s2, s1, keep2, keep1);
391 }
392 return intersectByArea(s1, s2, keep1, keep2);
393 }
394
395
396
397
398
399
400
401
402 Shape intersectRectShape(Rectangle2D r, Shape s,
403 boolean keep1, boolean keep2) {
404 if (s instanceof Rectangle2D) {
405 Rectangle2D r2 = (Rectangle2D) s;
406 Rectangle2D outrect;
407 if (!keep1) {
408 outrect = r;
409 } else if (!keep2) {
410 outrect = r2;
411 } else {
412 outrect = new Rectangle2D.Float();
413 }
414 double x1 = Math.max(r.getX(), r2.getX());
415 double x2 = Math.min(r.getX() + r.getWidth(),
416 r2.getX() + r2.getWidth());
417 double y1 = Math.max(r.getY(), r2.getY());
418 double y2 = Math.min(r.getY() + r.getHeight(),
419 r2.getY() + r2.getHeight());
420
421 if (((x2 - x1) < 0) || ((y2 - y1) < 0))
422
423 outrect.setFrameFromDiagonal(0, 0, 0, 0);
424 else
425 outrect.setFrameFromDiagonal(x1, y1, x2, y2);
426 return outrect;
427 }
428 if (r.contains(s.getBounds2D())) {
429 if (keep2) {
430 s = cloneShape(s);
431 }
432 return s;
433 }
434 return intersectByArea(r, s, keep1, keep2);
435 }
436
437 protected static Shape cloneShape(Shape s) {
438 return new GeneralPath(s);
439 }
440
441
442
443
444
445
446
447
448
449
450 Shape intersectByArea(Shape s1, Shape s2, boolean keep1, boolean keep2) {
451 Area a1, a2;
452
453
454
455 if (!keep1 && (s1 instanceof Area)) {
456 a1 = (Area) s1;
457 } else if (!keep2 && (s2 instanceof Area)) {
458 a1 = (Area) s2;
459 s2 = s1;
460 } else {
461 a1 = new Area(s1);
462 }
463
464 if (s2 instanceof Area) {
465 a2 = (Area) s2;
466 } else {
467 a2 = new Area(s2);
468 }
469
470 a1.intersect(a2);
471 if (a1.isRectangular()) {
472 return a1.getBounds();
473 }
474
475 return a1;
476 }
477
478
479
480
481
482 public Region getCompClip() {
483 if (!surfaceData.isValid()) {
484
485 revalidateAll();
486 }
487
488 return clipRegion;
489 }
490
491 public Font getFont() {
492 if (font == null) {
493 font = defaultFont;
494 }
495 return font;
496 }
497
498 private static final double[] IDENT_MATRIX = {1, 0, 0, 1};
499 private static final AffineTransform IDENT_ATX =
500 new AffineTransform();
501
502 private static final int MINALLOCATED = 8;
503 private static final int TEXTARRSIZE = 17;
504 private static double[][] textTxArr = new double[TEXTARRSIZE][];
505 private static AffineTransform[] textAtArr =
506 new AffineTransform[TEXTARRSIZE];
507
508 static {
509 for (int i=MINALLOCATED;i<TEXTARRSIZE;i++) {
510 textTxArr[i] = new double [] {i, 0, 0, i};
511 textAtArr[i] = new AffineTransform( textTxArr[i]);
512 }
513 }
514
515
516 public FontInfo checkFontInfo(FontInfo info, Font font,
517 FontRenderContext frc) {
518
519
520
521
522 if (info == null) {
523 info = new FontInfo();
524 }
525
526 float ptSize = font.getSize2D();
527 int txFontType;
528 AffineTransform devAt, textAt=null;
529 if (font.isTransformed()) {
530 textAt = font.getTransform();
531 textAt.scale(ptSize, ptSize);
532 txFontType = textAt.getType();
533 info.originX = (float)textAt.getTranslateX();
534 info.originY = (float)textAt.getTranslateY();
535 textAt.translate(-info.originX, -info.originY);
536 if (transformState >= TRANSFORM_TRANSLATESCALE) {
537 transform.getMatrix(info.devTx = new double[4]);
538 devAt = new AffineTransform(info.devTx);
539 textAt.preConcatenate(devAt);
540 } else {
541 info.devTx = IDENT_MATRIX;
542 devAt = IDENT_ATX;
543 }
544 textAt.getMatrix(info.glyphTx = new double[4]);
545 double shearx = textAt.getShearX();
546 double scaley = textAt.getScaleY();
547 if (shearx != 0) {
548 scaley = Math.sqrt(shearx * shearx + scaley * scaley);
549 }
550 info.pixelHeight = (int)(Math.abs(scaley)+0.5);
551 } else {
552 txFontType = AffineTransform.TYPE_IDENTITY;
553 info.originX = info.originY = 0;
554 if (transformState >= TRANSFORM_TRANSLATESCALE) {
555 transform.getMatrix(info.devTx = new double[4]);
556 devAt = new AffineTransform(info.devTx);
557 info.glyphTx = new double[4];
558 for (int i = 0; i < 4; i++) {
559 info.glyphTx[i] = info.devTx[i] * ptSize;
560 }
561 textAt = new AffineTransform(info.glyphTx);
562 double shearx = transform.getShearX();
563 double scaley = transform.getScaleY();
564 if (shearx != 0) {
565 scaley = Math.sqrt(shearx * shearx + scaley * scaley);
566 }
567 info.pixelHeight = (int)(Math.abs(scaley * ptSize)+0.5);
568 } else {
569
570
571
572
573
574
575
576
577 int pszInt = (int)ptSize;
578 if (ptSize == pszInt &&
579 pszInt >= MINALLOCATED && pszInt < TEXTARRSIZE) {
580 info.glyphTx = textTxArr[pszInt];
581 textAt = textAtArr[pszInt];
582 info.pixelHeight = pszInt;
583 } else {
584 info.pixelHeight = (int)(ptSize+0.5);
585 }
586 if (textAt == null) {
587 info.glyphTx = new double[] {ptSize, 0, 0, ptSize};
588 textAt = new AffineTransform(info.glyphTx);
589 }
590
591 info.devTx = IDENT_MATRIX;
592 devAt = IDENT_ATX;
593 }
594 }
595
596 info.font2D = FontUtilities.getFont2D(font);
597
598 int fmhint = fractionalMetricsHint;
599 if (fmhint == SunHints.INTVAL_FRACTIONALMETRICS_DEFAULT) {
600 fmhint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
601 }
602 info.lcdSubPixPos = false;
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626 int aahint;
627 if (frc == null) {
628 aahint = textAntialiasHint;
629 } else {
630 aahint = ((SunHints.Value)frc.getAntiAliasingHint()).getIndex();
631 }
632 if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT) {
633 if (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
634 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
635 } else {
636 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF;
637 }
638 } else {
639
640
641
642
643
644
645 if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP) {
646 if (info.font2D.useAAForPtSize(info.pixelHeight)) {
647 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
648 } else {
649 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF;
650 }
651 } else if (aahint >= SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB) {
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667 if (
668 !surfaceData.canRenderLCDText(this)
669
670
671
672 ) {
673 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
674 } else {
675 info.lcdRGBOrder = true;
676
677
678
679
680
681
682
683 if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HBGR) {
684 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB;
685 info.lcdRGBOrder = false;
686 } else if
687 (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VBGR) {
688 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB;
689 info.lcdRGBOrder = false;
690 }
691
692
693
694 info.lcdSubPixPos =
695 fmhint == SunHints.INTVAL_FRACTIONALMETRICS_ON &&
696 aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB;
697 }
698 }
699 }
700 info.aaHint = aahint;
701 info.fontStrike = info.font2D.getStrike(font, devAt, textAt,
702 aahint, fmhint);
703 return info;
704 }
705
706 public static boolean isRotated(double [] mtx) {
707 if ((mtx[0] == mtx[3]) &&
708 (mtx[1] == 0.0) &&
709 (mtx[2] == 0.0) &&
710 (mtx[0] > 0.0))
711 {
712 return false;
713 }
714
715 return true;
716 }
717
718 public void setFont(Font font) {
719
720
721
722
723
724 if (font != null && font!=this.font) {
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739 if (textAntialiasHint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP &&
740 textpipe != invalidpipe &&
741 (transformState > TRANSFORM_ANY_TRANSLATE ||
742 font.isTransformed() ||
743 fontInfo == null ||
744 (fontInfo.aaHint == SunHints.INTVAL_TEXT_ANTIALIAS_ON) !=
745 FontUtilities.getFont2D(font).
746 useAAForPtSize(font.getSize()))) {
747 textpipe = invalidpipe;
748 }
749 this.font = font;
750 this.fontMetrics = null;
751 this.validFontInfo = false;
752 }
753 }
754
755 public FontInfo getFontInfo() {
756 if (!validFontInfo) {
757 this.fontInfo = checkFontInfo(this.fontInfo, font, null);
758 validFontInfo = true;
759 }
760 return this.fontInfo;
761 }
762
763
764 public FontInfo getGVFontInfo(Font font, FontRenderContext frc) {
765 if (glyphVectorFontInfo != null &&
766 glyphVectorFontInfo.font == font &&
767 glyphVectorFRC == frc) {
768 return glyphVectorFontInfo;
769 } else {
770 glyphVectorFRC = frc;
771 return glyphVectorFontInfo =
772 checkFontInfo(glyphVectorFontInfo, font, frc);
773 }
774 }
775
776 public FontMetrics getFontMetrics() {
777 if (this.fontMetrics != null) {
778 return this.fontMetrics;
779 }
780
781 return this.fontMetrics =
782 FontDesignMetrics.getMetrics(font, getFontRenderContext());
783 }
784
785 public FontMetrics getFontMetrics(Font font) {
786 if ((this.fontMetrics != null) && (font == this.font)) {
787 return this.fontMetrics;
788 }
789 FontMetrics fm =
790 FontDesignMetrics.getMetrics(font, getFontRenderContext());
791
792 if (this.font == font) {
793 this.fontMetrics = fm;
794 }
795 return fm;
796 }
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815 public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
816 if (onStroke) {
817 s = stroke.createStrokedShape(s);
818 }
819
820 s = transformShape(s);
821 if ((constrainX|constrainY) != 0) {
822 rect = new Rectangle(rect);
823 rect.translate(constrainX, constrainY);
824 }
825
826 return s.intersects(rect);
827 }
828
829
830
831
832 public ColorModel getDeviceColorModel() {
833 return surfaceData.getColorModel();
834 }
835
836
837
838
839 public GraphicsConfiguration getDeviceConfiguration() {
840 return surfaceData.getDeviceConfiguration();
841 }
842
843
844
845
846
847 public final SurfaceData getSurfaceData() {
848 return surfaceData;
849 }
850
851
852
853
854
855
856
857
858
859
860
861 public void setComposite(Composite comp) {
862 if (composite == comp) {
863 return;
864 }
865 int newCompState;
866 CompositeType newCompType;
867 if (comp instanceof AlphaComposite) {
868 AlphaComposite alphacomp = (AlphaComposite) comp;
869 newCompType = CompositeType.forAlphaComposite(alphacomp);
870 if (newCompType == CompositeType.SrcOverNoEa) {
871 if (paintState == PAINT_OPAQUECOLOR ||
872 (paintState > PAINT_ALPHACOLOR &&
873 paint.getTransparency() == Transparency.OPAQUE))
874 {
875 newCompState = COMP_ISCOPY;
876 } else {
877 newCompState = COMP_ALPHA;
878 }
879 } else if (newCompType == CompositeType.SrcNoEa ||
880 newCompType == CompositeType.Src ||
881 newCompType == CompositeType.Clear)
882 {
883 newCompState = COMP_ISCOPY;
884 } else if (surfaceData.getTransparency() == Transparency.OPAQUE &&
885 newCompType == CompositeType.SrcIn)
886 {
887 newCompState = COMP_ISCOPY;
888 } else {
889 newCompState = COMP_ALPHA;
890 }
891 } else if (comp instanceof XORComposite) {
892 newCompState = COMP_XOR;
893 newCompType = CompositeType.Xor;
894 } else if (comp == null) {
895 throw new IllegalArgumentException("null Composite");
896 } else {
897 surfaceData.checkCustomComposite();
898 newCompState = COMP_CUSTOM;
899 newCompType = CompositeType.General;
900 }
901 if (compositeState != newCompState ||
902 imageComp != newCompType)
903 {
904 compositeState = newCompState;
905 imageComp = newCompType;
906 invalidatePipe();
907 validFontInfo = false;
908 }
909 composite = comp;
910 if (paintState <= PAINT_ALPHACOLOR) {
911 validateColor();
912 }
913 }
914
915
916
917
918
919
920
921
922
923 public void setPaint(Paint paint) {
924 if (paint instanceof Color) {
925 setColor((Color) paint);
926 return;
927 }
928 if (paint == null || this.paint == paint) {
929 return;
930 }
931 this.paint = paint;
932 if (imageComp == CompositeType.SrcOverNoEa) {
933
934 if (paint.getTransparency() == Transparency.OPAQUE) {
935 if (compositeState != COMP_ISCOPY) {
936 compositeState = COMP_ISCOPY;
937 }
938 } else {
939 if (compositeState == COMP_ISCOPY) {
940 compositeState = COMP_ALPHA;
941 }
942 }
943 }
944 Class paintClass = paint.getClass();
945 if (paintClass == GradientPaint.class) {
946 paintState = PAINT_GRADIENT;
947 } else if (paintClass == LinearGradientPaint.class) {
948 paintState = PAINT_LIN_GRADIENT;
949 } else if (paintClass == RadialGradientPaint.class) {
950 paintState = PAINT_RAD_GRADIENT;
951 } else if (paintClass == TexturePaint.class) {
952 paintState = PAINT_TEXTURE;
953 } else {
954 paintState = PAINT_CUSTOM;
955 }
956 validFontInfo = false;
957 invalidatePipe();
958 }
959
960 static final int NON_UNIFORM_SCALE_MASK =
961 (AffineTransform.TYPE_GENERAL_TRANSFORM |
962 AffineTransform.TYPE_GENERAL_SCALE);
963 public static final double MinPenSizeAA =
964 sun.java2d.pipe.RenderingEngine.getInstance().getMinimumAAPenSize();
965 public static final double MinPenSizeAASquared =
966 (MinPenSizeAA * MinPenSizeAA);
967
968
969
970
971
972 public static final double MinPenSizeSquared = 1.000000001;
973
974 private void validateBasicStroke(BasicStroke bs) {
975 boolean aa = (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON);
976 if (transformState < TRANSFORM_TRANSLATESCALE) {
977 if (aa) {
978 if (bs.getLineWidth() <= MinPenSizeAA) {
979 if (bs.getDashArray() == null) {
980 strokeState = STROKE_THIN;
981 } else {
982 strokeState = STROKE_THINDASHED;
983 }
984 } else {
985 strokeState = STROKE_WIDE;
986 }
987 } else {
988 if (bs == defaultStroke) {
989 strokeState = STROKE_THIN;
990 } else if (bs.getLineWidth() <= 1.0f) {
991 if (bs.getDashArray() == null) {
992 strokeState = STROKE_THIN;
993 } else {
994 strokeState = STROKE_THINDASHED;
995 }
996 } else {
997 strokeState = STROKE_WIDE;
998 }
999 }
1000 } else {
1001 double widthsquared;
1002 if ((transform.getType() & NON_UNIFORM_SCALE_MASK) == 0) {
1003
1004 widthsquared = Math.abs(transform.getDeterminant());
1005 } else {
1006
1007 double A = transform.getScaleX();
1008 double C = transform.getShearX();
1009 double B = transform.getShearY();
1010 double D = transform.getScaleY();
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 double EA = A*A + B*B;
1027 double EB = 2*(A*C + B*D);
1028 double EC = C*C + D*D;
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052 double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC));
1053
1054
1055 widthsquared = ((EA + EC + hypot)/2.0);
1056 }
1057 if (bs != defaultStroke) {
1058 widthsquared *= bs.getLineWidth() * bs.getLineWidth();
1059 }
1060 if (widthsquared <=
1061 (aa ? MinPenSizeAASquared : MinPenSizeSquared))
1062 {
1063 if (bs.getDashArray() == null) {
1064 strokeState = STROKE_THIN;
1065 } else {
1066 strokeState = STROKE_THINDASHED;
1067 }
1068 } else {
1069 strokeState = STROKE_WIDE;
1070 }
1071 }
1072 }
1073
1074
1075
1076
1077
1078
1079
1080 public void setStroke(Stroke s) {
1081 if (s == null) {
1082 throw new IllegalArgumentException("null Stroke");
1083 }
1084 int saveStrokeState = strokeState;
1085 stroke = s;
1086 if (s instanceof BasicStroke) {
1087 validateBasicStroke((BasicStroke) s);
1088 } else {
1089 strokeState = STROKE_CUSTOM;
1090 }
1091 if (strokeState != saveStrokeState) {
1092 invalidatePipe();
1093 }
1094 }
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 public void setRenderingHint(Key hintKey, Object hintValue) {
1108
1109
1110
1111
1112
1113 if (!hintKey.isCompatibleValue(hintValue)) {
1114 throw new IllegalArgumentException
1115 (hintValue+" is not compatible with "+hintKey);
1116 }
1117 if (hintKey instanceof SunHints.Key) {
1118 boolean stateChanged;
1119 boolean textStateChanged = false;
1120 boolean recognized = true;
1121 SunHints.Key sunKey = (SunHints.Key) hintKey;
1122 int newHint;
1123 if (sunKey == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST) {
1124 newHint = ((Integer)hintValue).intValue();
1125 } else {
1126 newHint = ((SunHints.Value) hintValue).getIndex();
1127 }
1128 switch (sunKey.getIndex()) {
1129 case SunHints.INTKEY_RENDERING:
1130 stateChanged = (renderHint != newHint);
1131 if (stateChanged) {
1132 renderHint = newHint;
1133 if (interpolationHint == -1) {
1134 interpolationType =
1135 (newHint == SunHints.INTVAL_RENDER_QUALITY
1136 ? AffineTransformOp.TYPE_BILINEAR
1137 : AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
1138 }
1139 }
1140 break;
1141 case SunHints.INTKEY_ANTIALIASING:
1142 stateChanged = (antialiasHint != newHint);
1143 antialiasHint = newHint;
1144 if (stateChanged) {
1145 textStateChanged =
1146 (textAntialiasHint ==
1147 SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT);
1148 if (strokeState != STROKE_CUSTOM) {
1149 validateBasicStroke((BasicStroke) stroke);
1150 }
1151 }
1152 break;
1153 case SunHints.INTKEY_TEXT_ANTIALIASING:
1154 stateChanged = (textAntialiasHint != newHint);
1155 textStateChanged = stateChanged;
1156 textAntialiasHint = newHint;
1157 break;
1158 case SunHints.INTKEY_FRACTIONALMETRICS:
1159 stateChanged = (fractionalMetricsHint != newHint);
1160 textStateChanged = stateChanged;
1161 fractionalMetricsHint = newHint;
1162 break;
1163 case SunHints.INTKEY_AATEXT_LCD_CONTRAST:
1164 stateChanged = false;
1165
1166 lcdTextContrast = newHint;
1167 break;
1168 case SunHints.INTKEY_INTERPOLATION:
1169 interpolationHint = newHint;
1170 switch (newHint) {
1171 case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1172 newHint = AffineTransformOp.TYPE_BICUBIC;
1173 break;
1174 case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1175 newHint = AffineTransformOp.TYPE_BILINEAR;
1176 break;
1177 default:
1178 case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1179 newHint = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
1180 break;
1181 }
1182 stateChanged = (interpolationType != newHint);
1183 interpolationType = newHint;
1184 break;
1185 case SunHints.INTKEY_STROKE_CONTROL:
1186 stateChanged = (strokeHint != newHint);
1187 strokeHint = newHint;
1188 break;
1189 default:
1190 recognized = false;
1191 stateChanged = false;
1192 break;
1193 }
1194 if (recognized) {
1195 if (stateChanged) {
1196 invalidatePipe();
1197 if (textStateChanged) {
1198 fontMetrics = null;
1199 this.cachedFRC = null;
1200 validFontInfo = false;
1201 this.glyphVectorFontInfo = null;
1202 }
1203 }
1204 if (hints != null) {
1205 hints.put(hintKey, hintValue);
1206 }
1207 return;
1208 }
1209 }
1210
1211 if (hints == null) {
1212 hints = makeHints(null);
1213 }
1214 hints.put(hintKey, hintValue);
1215 }
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 public Object getRenderingHint(Key hintKey) {
1227 if (hints != null) {
1228 return hints.get(hintKey);
1229 }
1230 if (!(hintKey instanceof SunHints.Key)) {
1231 return null;
1232 }
1233 int keyindex = ((SunHints.Key)hintKey).getIndex();
1234 switch (keyindex) {
1235 case SunHints.INTKEY_RENDERING:
1236 return SunHints.Value.get(SunHints.INTKEY_RENDERING,
1237 renderHint);
1238 case SunHints.INTKEY_ANTIALIASING:
1239 return SunHints.Value.get(SunHints.INTKEY_ANTIALIASING,
1240 antialiasHint);
1241 case SunHints.INTKEY_TEXT_ANTIALIASING:
1242 return SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,
1243 textAntialiasHint);
1244 case SunHints.INTKEY_FRACTIONALMETRICS:
1245 return SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,
1246 fractionalMetricsHint);
1247 case SunHints.INTKEY_AATEXT_LCD_CONTRAST:
1248 return new Integer(lcdTextContrast);
1249 case SunHints.INTKEY_INTERPOLATION:
1250 switch (interpolationHint) {
1251 case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1252 return SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
1253 case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1254 return SunHints.VALUE_INTERPOLATION_BILINEAR;
1255 case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1256 return SunHints.VALUE_INTERPOLATION_BICUBIC;
1257 }
1258 return null;
1259 case SunHints.INTKEY_STROKE_CONTROL:
1260 return SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,
1261 strokeHint);
1262 }
1263 return null;
1264 }
1265
1266
1267
1268
1269
1270
1271
1272
1273 public void setRenderingHints(Map<?,?> hints) {
1274 this.hints = null;
1275 renderHint = SunHints.INTVAL_RENDER_DEFAULT;
1276 antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
1277 textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
1278 fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
1279 lcdTextContrast = lcdTextContrastDefaultValue;
1280 interpolationHint = -1;
1281 interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
1282 boolean customHintPresent = false;
1283 Iterator iter = hints.keySet().iterator();
1284 while (iter.hasNext()) {
1285 Object key = iter.next();
1286 if (key == SunHints.KEY_RENDERING ||
1287 key == SunHints.KEY_ANTIALIASING ||
1288 key == SunHints.KEY_TEXT_ANTIALIASING ||
1289 key == SunHints.KEY_FRACTIONALMETRICS ||
1290 key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST ||
1291 key == SunHints.KEY_STROKE_CONTROL ||
1292 key == SunHints.KEY_INTERPOLATION)
1293 {
1294 setRenderingHint((Key) key, hints.get(key));
1295 } else {
1296 customHintPresent = true;
1297 }
1298 }
1299 if (customHintPresent) {
1300 this.hints = makeHints(hints);
1301 }
1302 invalidatePipe();
1303 }
1304
1305
1306
1307
1308
1309
1310
1311
1312 public void addRenderingHints(Map<?,?> hints) {
1313 boolean customHintPresent = false;
1314 Iterator iter = hints.keySet().iterator();
1315 while (iter.hasNext()) {
1316 Object key = iter.next();
1317 if (key == SunHints.KEY_RENDERING ||
1318 key == SunHints.KEY_ANTIALIASING ||
1319 key == SunHints.KEY_TEXT_ANTIALIASING ||
1320 key == SunHints.KEY_FRACTIONALMETRICS ||
1321 key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST ||
1322 key == SunHints.KEY_STROKE_CONTROL ||
1323 key == SunHints.KEY_INTERPOLATION)
1324 {
1325 setRenderingHint((Key) key, hints.get(key));
1326 } else {
1327 customHintPresent = true;
1328 }
1329 }
1330 if (customHintPresent) {
1331 if (this.hints == null) {
1332 this.hints = makeHints(hints);
1333 } else {
1334 this.hints.putAll(hints);
1335 }
1336 }
1337 }
1338
1339
1340
1341
1342
1343
1344
1345 public RenderingHints getRenderingHints() {
1346 if (hints == null) {
1347 return makeHints(null);
1348 } else {
1349 return (RenderingHints) hints.clone();
1350 }
1351 }
1352
1353 RenderingHints makeHints(Map hints) {
1354 RenderingHints model = new RenderingHints(hints);
1355 model.put(SunHints.KEY_RENDERING,
1356 SunHints.Value.get(SunHints.INTKEY_RENDERING,
1357 renderHint));
1358 model.put(SunHints.KEY_ANTIALIASING,
1359 SunHints.Value.get(SunHints.INTKEY_ANTIALIASING,
1360 antialiasHint));
1361 model.put(SunHints.KEY_TEXT_ANTIALIASING,
1362 SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,
1363 textAntialiasHint));
1364 model.put(SunHints.KEY_FRACTIONALMETRICS,
1365 SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,
1366 fractionalMetricsHint));
1367 model.put(SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST,
1368 Integer.valueOf(lcdTextContrast));
1369 Object value;
1370 switch (interpolationHint) {
1371 case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1372 value = SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
1373 break;
1374 case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1375 value = SunHints.VALUE_INTERPOLATION_BILINEAR;
1376 break;
1377 case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1378 value = SunHints.VALUE_INTERPOLATION_BICUBIC;
1379 break;
1380 default:
1381 value = null;
1382 break;
1383 }
1384 if (value != null) {
1385 model.put(SunHints.KEY_INTERPOLATION, value);
1386 }
1387 model.put(SunHints.KEY_STROKE_CONTROL,
1388 SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,
1389 strokeHint));
1390 return model;
1391 }
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404 public void translate(double tx, double ty) {
1405 transform.translate(tx, ty);
1406 invalidateTransform();
1407 }
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423 public void rotate(double theta) {
1424 transform.rotate(theta);
1425 invalidateTransform();
1426 }
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443 public void rotate(double theta, double x, double y) {
1444 transform.rotate(theta, x, y);
1445 invalidateTransform();
1446 }
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459 public void scale(double sx, double sy) {
1460 transform.scale(sx, sy);
1461 invalidateTransform();
1462 }
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479 public void shear(double shx, double shy) {
1480 transform.shear(shx, shy);
1481 invalidateTransform();
1482 }
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501 public void transform(AffineTransform xform) {
1502 this.transform.concatenate(xform);
1503 invalidateTransform();
1504 }
1505
1506
1507
1508
1509 public void translate(int x, int y) {
1510 transform.translate(x, y);
1511 if (transformState <= TRANSFORM_INT_TRANSLATE) {
1512 transX += x;
1513 transY += y;
1514 transformState = (((transX | transY) == 0) ?
1515 TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE);
1516 } else {
1517 invalidateTransform();
1518 }
1519 }
1520
1521
1522
1523
1524
1525
1526
1527
1528 public void setTransform(AffineTransform Tx) {
1529 if ((constrainX|constrainY) == 0) {
1530 transform.setTransform(Tx);
1531 } else {
1532 transform.setToTranslation(constrainX, constrainY);
1533 transform.concatenate(Tx);
1534 }
1535 invalidateTransform();
1536 }
1537
1538 protected void invalidateTransform() {
1539 int type = transform.getType();
1540 int origTransformState = transformState;
1541 if (type == AffineTransform.TYPE_IDENTITY) {
1542 transformState = TRANSFORM_ISIDENT;
1543 transX = transY = 0;
1544 } else if (type == AffineTransform.TYPE_TRANSLATION) {
1545 double dtx = transform.getTranslateX();
1546 double dty = transform.getTranslateY();
1547 transX = (int) Math.floor(dtx + 0.5);
1548 transY = (int) Math.floor(dty + 0.5);
1549 if (dtx == transX && dty == transY) {
1550 transformState = TRANSFORM_INT_TRANSLATE;
1551 } else {
1552 transformState = TRANSFORM_ANY_TRANSLATE;
1553 }
1554 } else if ((type & (AffineTransform.TYPE_FLIP |
1555 AffineTransform.TYPE_MASK_ROTATION |
1556 AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0)
1557 {
1558 transformState = TRANSFORM_TRANSLATESCALE;
1559 transX = transY = 0;
1560 } else {
1561 transformState = TRANSFORM_GENERIC;
1562 transX = transY = 0;
1563 }
1564
1565 if (transformState >= TRANSFORM_TRANSLATESCALE ||
1566 origTransformState >= TRANSFORM_TRANSLATESCALE)
1567 {
1568
1569
1570
1571 cachedFRC = null;
1572 this.validFontInfo = false;
1573 this.fontMetrics = null;
1574 this.glyphVectorFontInfo = null;
1575
1576 if (transformState != origTransformState) {
1577 invalidatePipe();
1578 }
1579 }
1580 if (strokeState != STROKE_CUSTOM) {
1581 validateBasicStroke((BasicStroke) stroke);
1582 }
1583 }
1584
1585
1586
1587
1588
1589
1590 public AffineTransform getTransform() {
1591 if ((constrainX|constrainY) == 0) {
1592 return new AffineTransform(transform);
1593 }
1594 AffineTransform tx =
1595 AffineTransform.getTranslateInstance(-constrainX, -constrainY);
1596 tx.concatenate(transform);
1597 return tx;
1598 }
1599
1600
1601
1602
1603
1604 public AffineTransform cloneTransform() {
1605 return new AffineTransform(transform);
1606 }
1607
1608
1609
1610
1611
1612
1613 public Paint getPaint() {
1614 return paint;
1615 }
1616
1617
1618
1619
1620
1621 public Composite getComposite() {
1622 return composite;
1623 }
1624
1625 public Color getColor() {
1626 return foregroundColor;
1627 }
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649 final void validateColor() {
1650 int eargb;
1651 if (imageComp == CompositeType.Clear) {
1652 eargb = 0;
1653 } else {
1654 eargb = foregroundColor.getRGB();
1655 if (compositeState <= COMP_ALPHA &&
1656 imageComp != CompositeType.SrcNoEa &&
1657 imageComp != CompositeType.SrcOverNoEa)
1658 {
1659 AlphaComposite alphacomp = (AlphaComposite) composite;
1660 int a = Math.round(alphacomp.getAlpha() * (eargb >>> 24));
1661 eargb = (eargb & 0x00ffffff) | (a << 24);
1662 }
1663 }
1664 this.eargb = eargb;
1665 this.pixel = surfaceData.pixelFor(eargb);
1666 }
1667
1668 public void setColor(Color color) {
1669 if (color == null || color == paint) {
1670 return;
1671 }
1672 this.paint = foregroundColor = color;
1673 validateColor();
1674 if ((eargb >> 24) == -1) {
1675 if (paintState == PAINT_OPAQUECOLOR) {
1676 return;
1677 }
1678 paintState = PAINT_OPAQUECOLOR;
1679 if (imageComp == CompositeType.SrcOverNoEa) {
1680
1681 compositeState = COMP_ISCOPY;
1682 }
1683 } else {
1684 if (paintState == PAINT_ALPHACOLOR) {
1685 return;
1686 }
1687 paintState = PAINT_ALPHACOLOR;
1688 if (imageComp == CompositeType.SrcOverNoEa) {
1689
1690 compositeState = COMP_ALPHA;
1691 }
1692 }
1693 validFontInfo = false;
1694 invalidatePipe();
1695 }
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709 public void setBackground(Color color) {
1710 backgroundColor = color;
1711 }
1712
1713
1714
1715
1716
1717 public Color getBackground() {
1718 return backgroundColor;
1719 }
1720
1721
1722
1723
1724
1725 public Stroke getStroke() {
1726 return stroke;
1727 }
1728
1729 public Rectangle getClipBounds() {
1730 Rectangle r;
1731 if (clipState == CLIP_DEVICE) {
1732 r = null;
1733 } else if (transformState <= TRANSFORM_INT_TRANSLATE) {
1734 if (usrClip instanceof Rectangle) {
1735 r = new Rectangle((Rectangle) usrClip);
1736 } else {
1737 r = usrClip.getBounds();
1738 }
1739 r.translate(-transX, -transY);
1740 } else {
1741 r = getClip().getBounds();
1742 }
1743 return r;
1744 }
1745
1746 public Rectangle getClipBounds(Rectangle r) {
1747 if (clipState != CLIP_DEVICE) {
1748 if (transformState <= TRANSFORM_INT_TRANSLATE) {
1749 if (usrClip instanceof Rectangle) {
1750 r.setBounds((Rectangle) usrClip);
1751 } else {
1752 r.setBounds(usrClip.getBounds());
1753 }
1754 r.translate(-transX, -transY);
1755 } else {
1756 r.setBounds(getClip().getBounds());
1757 }
1758 } else if (r == null) {
1759 throw new NullPointerException("null rectangle parameter");
1760 }
1761 return r;
1762 }
1763
1764 public boolean hitClip(int x, int y, int width, int height) {
1765 if (width <= 0 || height <= 0) {
1766 return false;
1767 }
1768 if (transformState > TRANSFORM_INT_TRANSLATE) {
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786 double d[] = {
1787 x, y,
1788 x+width, y,
1789 x, y+height,
1790 x+width, y+height
1791 };
1792 transform.transform(d, 0, d, 0, 4);
1793 x = (int) Math.floor(Math.min(Math.min(d[0], d[2]),
1794 Math.min(d[4], d[6])));
1795 y = (int) Math.floor(Math.min(Math.min(d[1], d[3]),
1796 Math.min(d[5], d[7])));
1797 width = (int) Math.ceil(Math.max(Math.max(d[0], d[2]),
1798 Math.max(d[4], d[6])));
1799 height = (int) Math.ceil(Math.max(Math.max(d[1], d[3]),
1800 Math.max(d[5], d[7])));
1801 } else {
1802 x += transX;
1803 y += transY;
1804 width += x;
1805 height += y;
1806 }
1807 if (!getCompClip().intersectsQuickCheckXYXY(x, y, width, height)) {
1808 return false;
1809 }
1810
1811
1812
1813
1814
1815 return true;
1816 }
1817
1818 protected void validateCompClip() {
1819 int origClipState = clipState;
1820 if (usrClip == null) {
1821 clipState = CLIP_DEVICE;
1822 clipRegion = devClip;
1823 } else if (usrClip instanceof Rectangle2D) {
1824 clipState = CLIP_RECTANGULAR;
1825 if (usrClip instanceof Rectangle) {
1826 clipRegion = devClip.getIntersection((Rectangle)usrClip);
1827 } else {
1828 clipRegion = devClip.getIntersection(usrClip.getBounds());
1829 }
1830 } else {
1831 PathIterator cpi = usrClip.getPathIterator(null);
1832 int box[] = new int[4];
1833 ShapeSpanIterator sr = LoopPipe.getFillSSI(this);
1834 try {
1835 sr.setOutputArea(devClip);
1836 sr.appendPath(cpi);
1837 sr.getPathBox(box);
1838 Region r = Region.getInstance(box);
1839 r.appendSpans(sr);
1840 clipRegion = r;
1841 clipState =
1842 r.isRectangular() ? CLIP_RECTANGULAR : CLIP_SHAPE;
1843 } finally {
1844 sr.dispose();
1845 }
1846 }
1847 if (origClipState != clipState &&
1848 (clipState == CLIP_SHAPE || origClipState == CLIP_SHAPE))
1849 {
1850 validFontInfo = false;
1851 invalidatePipe();
1852 }
1853 }
1854
1855 static final int NON_RECTILINEAR_TRANSFORM_MASK =
1856 (AffineTransform.TYPE_GENERAL_TRANSFORM |
1857 AffineTransform.TYPE_GENERAL_ROTATION);
1858
1859 protected Shape transformShape(Shape s) {
1860 if (s == null) {
1861 return null;
1862 }
1863 if (transformState > TRANSFORM_INT_TRANSLATE) {
1864 return transformShape(transform, s);
1865 } else {
1866 return transformShape(transX, transY, s);
1867 }
1868 }
1869
1870 public Shape untransformShape(Shape s) {
1871 if (s == null) {
1872 return null;
1873 }
1874 if (transformState > TRANSFORM_INT_TRANSLATE) {
1875 try {
1876 return transformShape(transform.createInverse(), s);
1877 } catch (NoninvertibleTransformException e) {
1878 return null;
1879 }
1880 } else {
1881 return transformShape(-transX, -transY, s);
1882 }
1883 }
1884
1885 protected static Shape transformShape(int tx, int ty, Shape s) {
1886 if (s == null) {
1887 return null;
1888 }
1889
1890 if (s instanceof Rectangle) {
1891 Rectangle r = s.getBounds();
1892 r.translate(tx, ty);
1893 return r;
1894 }
1895 if (s instanceof Rectangle2D) {
1896 Rectangle2D rect = (Rectangle2D) s;
1897 return new Rectangle2D.Double(rect.getX() + tx,
1898 rect.getY() + ty,
1899 rect.getWidth(),
1900 rect.getHeight());
1901 }
1902
1903 if (tx == 0 && ty == 0) {
1904 return cloneShape(s);
1905 }
1906
1907 AffineTransform mat = AffineTransform.getTranslateInstance(tx, ty);
1908 return mat.createTransformedShape(s);
1909 }
1910
1911 protected static Shape transformShape(AffineTransform tx, Shape clip) {
1912 if (clip == null) {
1913 return null;
1914 }
1915
1916 if (clip instanceof Rectangle2D &&
1917 (tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0)
1918 {
1919 Rectangle2D rect = (Rectangle2D) clip;
1920 double matrix[] = new double[4];
1921 matrix[0] = rect.getX();
1922 matrix[1] = rect.getY();
1923 matrix[2] = matrix[0] + rect.getWidth();
1924 matrix[3] = matrix[1] + rect.getHeight();
1925 tx.transform(matrix, 0, matrix, 0, 2);
1926 rect = new Rectangle2D.Float();
1927 rect.setFrameFromDiagonal(matrix[0], matrix[1],
1928 matrix[2], matrix[3]);
1929 return rect;
1930 }
1931
1932 if (tx.isIdentity()) {
1933 return cloneShape(clip);
1934 }
1935
1936 return tx.createTransformedShape(clip);
1937 }
1938
1939 public void clipRect(int x, int y, int w, int h) {
1940 clip(new Rectangle(x, y, w, h));
1941 }
1942
1943 public void setClip(int x, int y, int w, int h) {
1944 setClip(new Rectangle(x, y, w, h));
1945 }
1946
1947 public Shape getClip() {
1948 return untransformShape(usrClip);
1949 }
1950
1951 public void setClip(Shape sh) {
1952 usrClip = transformShape(sh);
1953 validateCompClip();
1954 }
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964 public void clip(Shape s) {
1965 s = transformShape(s);
1966 if (usrClip != null) {
1967 s = intersectShapes(usrClip, s, true, true);
1968 }
1969 usrClip = s;
1970 validateCompClip();
1971 }
1972
1973 public void setPaintMode() {
1974 setComposite(AlphaComposite.SrcOver);
1975 }
1976
1977 public void setXORMode(Color c) {
1978 if (c == null) {
1979 throw new IllegalArgumentException("null XORColor");
1980 }
1981 setComposite(new XORComposite(c, surfaceData));
1982 }
1983
1984 Blit lastCAblit;
1985 Composite lastCAcomp;
1986
1987 public void copyArea(int x, int y, int w, int h, int dx, int dy) {
1988 try {
1989 doCopyArea(x, y, w, h, dx, dy);
1990 } catch (InvalidPipeException e) {
1991 revalidateAll();
1992 try {
1993 doCopyArea(x, y, w, h, dx, dy);
1994 } catch (InvalidPipeException e2) {
1995
1996
1997
1998 }
1999 } finally {
2000 surfaceData.markDirty();
2001 }
2002 }
2003
2004 private void doCopyArea(int x, int y, int w, int h, int dx, int dy) {
2005 if (w <= 0 || h <= 0) {
2006 return;
2007 }
2008 SurfaceData theData = surfaceData;
2009 if (theData.copyArea(this, x, y, w, h, dx, dy)) {
2010 return;
2011 }
2012 if (transformState >= TRANSFORM_TRANSLATESCALE) {
2013 throw new InternalError("transformed copyArea not implemented yet");
2014 }
2015
2016
2017
2018 Region clip = getCompClip();
2019
2020 Composite comp = composite;
2021 if (lastCAcomp != comp) {
2022 SurfaceType dsttype = theData.getSurfaceType();
2023 CompositeType comptype = imageComp;
2024 if (CompositeType.SrcOverNoEa.equals(comptype) &&
2025 theData.getTransparency() == Transparency.OPAQUE)
2026 {
2027 comptype = CompositeType.SrcNoEa;
2028 }
2029 lastCAblit = Blit.locate(dsttype, comptype, dsttype);
2030 lastCAcomp = comp;
2031 }
2032
2033 x += transX;
2034 y += transY;
2035
2036 Blit ob = lastCAblit;
2037 if (dy == 0 && dx > 0 && dx < w) {
2038 while (w > 0) {
2039 int partW = Math.min(w, dx);
2040 w -= partW;
2041 int sx = x + w;
2042 ob.Blit(theData, theData, comp, clip,
2043 sx, y, sx+dx, y+dy, partW, h);
2044 }
2045 return;
2046 }
2047 if (dy > 0 && dy < h && dx > -w && dx < w) {
2048 while (h > 0) {
2049 int partH = Math.min(h, dy);
2050 h -= partH;
2051 int sy = y + h;
2052 ob.Blit(theData, theData, comp, clip,
2053 x, sy, x+dx, sy+dy, w, partH);
2054 }
2055 return;
2056 }
2057 ob.Blit(theData, theData, comp, clip, x, y, x+dx, y+dy, w, h);
2058 }
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119 public void drawLine(int x1, int y1, int x2, int y2) {
2120 try {
2121 drawpipe.drawLine(this, x1, y1, x2, y2);
2122 } catch (InvalidPipeException e) {
2123 revalidateAll();
2124 try {
2125 drawpipe.drawLine(this, x1, y1, x2, y2);
2126 } catch (InvalidPipeException e2) {
2127
2128
2129
2130 }
2131 } finally {
2132 surfaceData.markDirty();
2133 }
2134 }
2135
2136 public void drawRoundRect(int x, int y, int w, int h, int arcW, int arcH) {
2137 try {
2138 drawpipe.drawRoundRect(this, x, y, w, h, arcW, arcH);
2139 } catch (InvalidPipeException e) {
2140 revalidateAll();
2141 try {
2142 drawpipe.drawRoundRect(this, x, y, w, h, arcW, arcH);
2143 } catch (InvalidPipeException e2) {
2144
2145
2146
2147 }
2148 } finally {
2149 surfaceData.markDirty();
2150 }
2151 }
2152
2153 public void fillRoundRect(int x, int y, int w, int h, int arcW, int arcH) {
2154 try {
2155 fillpipe.fillRoundRect(this, x, y, w, h, arcW, arcH);
2156 } catch (InvalidPipeException e) {
2157 revalidateAll();
2158 try {
2159 fillpipe.fillRoundRect(this, x, y, w, h, arcW, arcH);
2160 } catch (InvalidPipeException e2) {
2161
2162
2163
2164 }
2165 } finally {
2166 surfaceData.markDirty();
2167 }
2168 }
2169
2170 public void drawOval(int x, int y, int w, int h) {
2171 try {
2172 drawpipe.drawOval(this, x, y, w, h);
2173 } catch (InvalidPipeException e) {
2174 revalidateAll();
2175 try {
2176 drawpipe.drawOval(this, x, y, w, h);
2177 } catch (InvalidPipeException e2) {
2178
2179
2180
2181 }
2182 } finally {
2183 surfaceData.markDirty();
2184 }
2185 }
2186
2187 public void fillOval(int x, int y, int w, int h) {
2188 try {
2189 fillpipe.fillOval(this, x, y, w, h);
2190 } catch (InvalidPipeException e) {
2191 revalidateAll();
2192 try {
2193 fillpipe.fillOval(this, x, y, w, h);
2194 } catch (InvalidPipeException e2) {
2195
2196
2197
2198 }
2199 } finally {
2200 surfaceData.markDirty();
2201 }
2202 }
2203
2204 public void drawArc(int x, int y, int w, int h,
2205 int startAngl, int arcAngl) {
2206 try {
2207 drawpipe.drawArc(this, x, y, w, h, startAngl, arcAngl);
2208 } catch (InvalidPipeException e) {
2209 revalidateAll();
2210 try {
2211 drawpipe.drawArc(this, x, y, w, h, startAngl, arcAngl);
2212 } catch (InvalidPipeException e2) {
2213
2214
2215
2216 }
2217 } finally {
2218 surfaceData.markDirty();
2219 }
2220 }
2221
2222 public void fillArc(int x, int y, int w, int h,
2223 int startAngl, int arcAngl) {
2224 try {
2225 fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl);
2226 } catch (InvalidPipeException e) {
2227 revalidateAll();
2228 try {
2229 fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl);
2230 } catch (InvalidPipeException e2) {
2231
2232
2233
2234 }
2235 } finally {
2236 surfaceData.markDirty();
2237 }
2238 }
2239
2240 public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {
2241 try {
2242 drawpipe.drawPolyline(this, xPoints, yPoints, nPoints);
2243 } catch (InvalidPipeException e) {
2244 revalidateAll();
2245 try {
2246 drawpipe.drawPolyline(this, xPoints, yPoints, nPoints);
2247 } catch (InvalidPipeException e2) {
2248
2249
2250
2251 }
2252 } finally {
2253 surfaceData.markDirty();
2254 }
2255 }
2256
2257 public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {
2258 try {
2259 drawpipe.drawPolygon(this, xPoints, yPoints, nPoints);
2260 } catch (InvalidPipeException e) {
2261 revalidateAll();
2262 try {
2263 drawpipe.drawPolygon(this, xPoints, yPoints, nPoints);
2264 } catch (InvalidPipeException e2) {
2265
2266
2267
2268 }
2269 } finally {
2270 surfaceData.markDirty();
2271 }
2272 }
2273
2274 public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
2275 try {
2276 fillpipe.fillPolygon(this, xPoints, yPoints, nPoints);
2277 } catch (InvalidPipeException e) {
2278 revalidateAll();
2279 try {
2280 fillpipe.fillPolygon(this, xPoints, yPoints, nPoints);
2281 } catch (InvalidPipeException e2) {
2282
2283
2284
2285 }
2286 } finally {
2287 surfaceData.markDirty();
2288 }
2289 }
2290
2291 public void drawRect (int x, int y, int w, int h) {
2292 try {
2293 drawpipe.drawRect(this, x, y, w, h);
2294 } catch (InvalidPipeException e) {
2295 revalidateAll();
2296 try {
2297 drawpipe.drawRect(this, x, y, w, h);
2298 } catch (InvalidPipeException e2) {
2299
2300
2301
2302 }
2303 } finally {
2304 surfaceData.markDirty();
2305 }
2306 }
2307
2308 public void fillRect (int x, int y, int w, int h) {
2309 try {
2310 fillpipe.fillRect(this, x, y, w, h);
2311 } catch (InvalidPipeException e) {
2312 revalidateAll();
2313 try {
2314 fillpipe.fillRect(this, x, y, w, h);
2315 } catch (InvalidPipeException e2) {
2316
2317
2318
2319 }
2320 } finally {
2321 surfaceData.markDirty();
2322 }
2323 }
2324
2325 private void revalidateAll() {
2326 try {
2327
2328
2329
2330
2331
2332 surfaceData = surfaceData.getReplacement();
2333 if (surfaceData == null) {
2334 surfaceData = NullSurfaceData.theInstance;
2335 }
2336
2337
2338 setDevClip(surfaceData.getBounds());
2339
2340 if (paintState <= PAINT_ALPHACOLOR) {
2341 validateColor();
2342 }
2343 if (composite instanceof XORComposite) {
2344 Color c = ((XORComposite) composite).getXorColor();
2345 setComposite(new XORComposite(c, surfaceData));
2346 }
2347 validatePipe();
2348 } finally {
2349
2350
2351 }
2352 }
2353
2354 public void clearRect(int x, int y, int w, int h) {
2355
2356
2357 Composite c = composite;
2358 Paint p = paint;
2359 setComposite(AlphaComposite.Src);
2360 setColor(getBackground());
2361 validatePipe();
2362 fillRect(x, y, w, h);
2363 setPaint(p);
2364 setComposite(c);
2365 }
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381 public void draw(Shape s) {
2382 try {
2383 shapepipe.draw(this, s);
2384 } catch (InvalidPipeException e) {
2385 revalidateAll();
2386 try {
2387 shapepipe.draw(this, s);
2388 } catch (InvalidPipeException e2) {
2389
2390
2391
2392 }
2393 } finally {
2394 surfaceData.markDirty();
2395 }
2396 }
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411 public void fill(Shape s) {
2412 try {
2413 shapepipe.fill(this, s);
2414 } catch (InvalidPipeException e) {
2415 revalidateAll();
2416 try {
2417 shapepipe.fill(this, s);
2418 } catch (InvalidPipeException e2) {
2419
2420
2421
2422 }
2423 } finally {
2424 surfaceData.markDirty();
2425 }
2426 }
2427
2428
2429
2430
2431
2432 private static boolean isIntegerTranslation(AffineTransform xform) {
2433 if (xform.isIdentity()) {
2434 return true;
2435 }
2436 if (xform.getType() == AffineTransform.TYPE_TRANSLATION) {
2437 double tx = xform.getTranslateX();
2438 double ty = xform.getTranslateY();
2439 return (tx == (int)tx && ty == (int)ty);
2440 }
2441 return false;
2442 }
2443
2444
2445
2446
2447
2448 private static int getTileIndex(int p, int tileGridOffset, int tileSize) {
2449 p -= tileGridOffset;
2450 if (p < 0) {
2451 p += 1 - tileSize;
2452 }
2453 return p/tileSize;
2454 }
2455
2456
2457
2458
2459
2460
2461
2462
2463 private static Rectangle getImageRegion(RenderedImage img,
2464 Region compClip,
2465 AffineTransform transform,
2466 AffineTransform xform,
2467 int padX, int padY) {
2468 Rectangle imageRect =
2469 new Rectangle(img.getMinX(), img.getMinY(),
2470 img.getWidth(), img.getHeight());
2471
2472 Rectangle result = null;
2473 try {
2474 double p[] = new double[8];
2475 p[0] = p[2] = compClip.getLoX();
2476 p[4] = p[6] = compClip.getHiX();
2477 p[1] = p[5] = compClip.getLoY();
2478 p[3] = p[7] = compClip.getHiY();
2479
2480
2481 transform.inverseTransform(p, 0, p, 0, 4);
2482 xform.inverseTransform(p, 0, p, 0, 4);
2483
2484
2485 double x0,x1,y0,y1;
2486 x0 = x1 = p[0];
2487 y0 = y1 = p[1];
2488
2489 for (int i = 2; i < 8; ) {
2490 double pt = p[i++];
2491 if (pt < x0) {
2492 x0 = pt;
2493 } else if (pt > x1) {
2494 x1 = pt;
2495 }
2496 pt = p[i++];
2497 if (pt < y0) {
2498 y0 = pt;
2499 } else if (pt > y1) {
2500 y1 = pt;
2501 }
2502 }
2503
2504
2505
2506 int x = (int)x0 - padX;
2507 int w = (int)(x1 - x0 + 2*padX);
2508 int y = (int)y0 - padY;
2509 int h = (int)(y1 - y0 + 2*padY);
2510
2511 Rectangle clipRect = new Rectangle(x,y,w,h);
2512 result = clipRect.intersection(imageRect);
2513 } catch (NoninvertibleTransformException nte) {
2514
2515 result = imageRect;
2516 }
2517
2518 return result;
2519 }
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539 public void drawRenderedImage(RenderedImage img,
2540 AffineTransform xform) {
2541
2542 if (img == null) {
2543 return;
2544 }
2545
2546
2547 if (img instanceof BufferedImage) {
2548 BufferedImage bufImg = (BufferedImage)img;
2549 drawImage(bufImg,xform,null);
2550 return;
2551 }
2552
2553
2554
2555
2556 boolean isIntegerTranslate =
2557 (transformState <= TRANSFORM_INT_TRANSLATE) &&
2558 isIntegerTranslation(xform);
2559
2560
2561 int pad = isIntegerTranslate ? 0 : 3;
2562
2563
2564
2565 Rectangle region = getImageRegion(img,
2566 getCompClip(),
2567 transform,
2568 xform,
2569 pad, pad);
2570 if (region.width <= 0 || region.height <= 0) {
2571 return;
2572 }
2573
2574
2575
2576
2577
2578
2579 if (isIntegerTranslate) {
2580
2581
2582
2583
2584
2585
2586 drawTranslatedRenderedImage(img, region,
2587 (int) xform.getTranslateX(),
2588 (int) xform.getTranslateY());
2589 return;
2590 }
2591
2592
2593 Raster raster = img.getData(region);
2594
2595
2596
2597
2598 WritableRaster wRaster =
2599 Raster.createWritableRaster(raster.getSampleModel(),
2600 raster.getDataBuffer(),
2601 null);
2602
2603
2604
2605
2606
2607
2608 int minX = raster.getMinX();
2609 int minY = raster.getMinY();
2610 int width = raster.getWidth();
2611 int height = raster.getHeight();
2612 int px = minX - raster.getSampleModelTranslateX();
2613 int py = minY - raster.getSampleModelTranslateY();
2614 if (px != 0 || py != 0 || width != wRaster.getWidth() ||
2615 height != wRaster.getHeight()) {
2616 wRaster =
2617 wRaster.createWritableChild(px,
2618 py,
2619 width,
2620 height,
2621 0, 0,
2622 null);
2623 }
2624
2625
2626
2627
2628
2629 AffineTransform transXform = (AffineTransform)xform.clone();
2630 transXform.translate(minX, minY);
2631
2632 ColorModel cm = img.getColorModel();
2633 BufferedImage bufImg = new BufferedImage(cm,
2634 wRaster,
2635 cm.isAlphaPremultiplied(),
2636 null);
2637 drawImage(bufImg, transXform, null);
2638 }
2639
2640
2641
2642
2643
2644
2645 private boolean clipTo(Rectangle destRect, Rectangle clip) {
2646 int x1 = Math.max(destRect.x, clip.x);
2647 int x2 = Math.min(destRect.x + destRect.width, clip.x + clip.width);
2648 int y1 = Math.max(destRect.y, clip.y);
2649 int y2 = Math.min(destRect.y + destRect.height, clip.y + clip.height);
2650 if (((x2 - x1) < 0) || ((y2 - y1) < 0)) {
2651 destRect.width = -1;
2652 destRect.height = -1;
2653 return false;
2654 } else {
2655 destRect.x = x1;
2656 destRect.y = y1;
2657 destRect.width = x2 - x1;
2658 destRect.height = y2 - y1;
2659 return true;
2660 }
2661 }
2662
2663
2664
2665
2666
2667
2668 private void drawTranslatedRenderedImage(RenderedImage img,
2669 Rectangle region,
2670 int i2uTransX,
2671 int i2uTransY) {
2672
2673 int tileGridXOffset = img.getTileGridXOffset();
2674 int tileGridYOffset = img.getTileGridYOffset();
2675 int tileWidth = img.getTileWidth();
2676 int tileHeight = img.getTileHeight();
2677
2678
2679 int minTileX =
2680 getTileIndex(region.x, tileGridXOffset, tileWidth);
2681 int minTileY =
2682 getTileIndex(region.y, tileGridYOffset, tileHeight);
2683 int maxTileX =
2684 getTileIndex(region.x + region.width - 1,
2685 tileGridXOffset, tileWidth);
2686 int maxTileY =
2687 getTileIndex(region.y + region.height - 1,
2688 tileGridYOffset, tileHeight);
2689
2690
2691 ColorModel colorModel = img.getColorModel();
2692
2693
2694 Rectangle tileRect = new Rectangle();
2695
2696 for (int ty = minTileY; ty <= maxTileY; ty++) {
2697 for (int tx = minTileX; tx <= maxTileX; tx++) {
2698
2699 Raster raster = img.getTile(tx, ty);
2700
2701
2702 tileRect.x = tx*tileWidth + tileGridXOffset;
2703 tileRect.y = ty*tileHeight + tileGridYOffset;
2704 tileRect.width = tileWidth;
2705 tileRect.height = tileHeight;
2706
2707
2708
2709
2710 clipTo(tileRect, region);
2711
2712
2713 WritableRaster wRaster = null;
2714 if (raster instanceof WritableRaster) {
2715 wRaster = (WritableRaster)raster;
2716 } else {
2717
2718
2719 wRaster =
2720 Raster.createWritableRaster(raster.getSampleModel(),
2721 raster.getDataBuffer(),
2722 null);
2723 }
2724
2725
2726
2727 wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y,
2728 tileRect.width,
2729 tileRect.height,
2730 0, 0,
2731 null);
2732
2733
2734 BufferedImage bufImg =
2735 new BufferedImage(colorModel,
2736 wRaster,
2737 colorModel.isAlphaPremultiplied(),
2738 null);
2739
2740
2741
2742
2743
2744
2745 copyImage(bufImg, tileRect.x + i2uTransX,
2746 tileRect.y + i2uTransY, 0, 0, tileRect.width,
2747 tileRect.height, null, null);
2748 }
2749 }
2750 }
2751
2752 public void drawRenderableImage(RenderableImage img,
2753 AffineTransform xform) {
2754
2755 if (img == null) {
2756 return;
2757 }
2758
2759 AffineTransform pipeTransform = transform;
2760 AffineTransform concatTransform = new AffineTransform(xform);
2761 concatTransform.concatenate(pipeTransform);
2762 AffineTransform reverseTransform;
2763
2764 RenderContext rc = new RenderContext(concatTransform);
2765
2766 try {
2767 reverseTransform = pipeTransform.createInverse();
2768 } catch (NoninvertibleTransformException nte) {
2769 rc = new RenderContext(pipeTransform);
2770 reverseTransform = new AffineTransform();
2771 }
2772
2773 RenderedImage rendering = img.createRendering(rc);
2774 drawRenderedImage(rendering,reverseTransform);
2775 }
2776
2777
2778
2779
2780
2781
2782 protected Rectangle transformBounds(Rectangle rect,
2783 AffineTransform tx) {
2784 if (tx.isIdentity()) {
2785 return rect;
2786 }
2787
2788 Shape s = transformShape(tx, rect);
2789 return s.getBounds();
2790 }
2791
2792
2793 public void drawString(String str, int x, int y) {
2794 if (str == null) {
2795 throw new NullPointerException("String is null");
2796 }
2797
2798 if (font.hasLayoutAttributes()) {
2799 if (str.length() == 0) {
2800 return;
2801 }
2802 new TextLayout(str, font, getFontRenderContext()).draw(this, x, y);
2803 return;
2804 }
2805
2806 try {
2807 textpipe.drawString(this, str, x, y);
2808 } catch (InvalidPipeException e) {
2809 revalidateAll();
2810 try {
2811 textpipe.drawString(this, str, x, y);
2812 } catch (InvalidPipeException e2) {
2813
2814
2815
2816 }
2817 } finally {
2818 surfaceData.markDirty();
2819 }
2820 }
2821
2822 public void drawString(String str, float x, float y) {
2823 if (str == null) {
2824 throw new NullPointerException("String is null");
2825 }
2826
2827 if (font.hasLayoutAttributes()) {
2828 if (str.length() == 0) {
2829 return;
2830 }
2831 new TextLayout(str, font, getFontRenderContext()).draw(this, x, y);
2832 return;
2833 }
2834
2835 try {
2836 textpipe.drawString(this, str, x, y);
2837 } catch (InvalidPipeException e) {
2838 revalidateAll();
2839 try {
2840 textpipe.drawString(this, str, x, y);
2841 } catch (InvalidPipeException e2) {
2842
2843
2844
2845 }
2846 } finally {
2847 surfaceData.markDirty();
2848 }
2849 }
2850
2851 public void drawString(AttributedCharacterIterator iterator,
2852 int x, int y) {
2853 if (iterator == null) {
2854 throw new NullPointerException("AttributedCharacterIterator is null");
2855 }
2856 if (iterator.getBeginIndex() == iterator.getEndIndex()) {
2857 return;
2858 }
2859 TextLayout tl = new TextLayout(iterator, getFontRenderContext());
2860 tl.draw(this, (float) x, (float) y);
2861 }
2862
2863 public void drawString(AttributedCharacterIterator iterator,
2864 float x, float y) {
2865 if (iterator == null) {
2866 throw new NullPointerException("AttributedCharacterIterator is null");
2867 }
2868 if (iterator.getBeginIndex() == iterator.getEndIndex()) {
2869 return;
2870 }
2871 TextLayout tl = new TextLayout(iterator, getFontRenderContext());
2872 tl.draw(this, x, y);
2873 }
2874
2875 public void drawGlyphVector(GlyphVector gv, float x, float y)
2876 {
2877 if (gv == null) {
2878 throw new NullPointerException("GlyphVector is null");
2879 }
2880
2881 try {
2882 textpipe.drawGlyphVector(this, gv, x, y);
2883 } catch (InvalidPipeException e) {
2884 revalidateAll();
2885 try {
2886 textpipe.drawGlyphVector(this, gv, x, y);
2887 } catch (InvalidPipeException e2) {
2888
2889
2890
2891 }
2892 } finally {
2893 surfaceData.markDirty();
2894 }
2895 }
2896
2897 public void drawChars(char data[], int offset, int length, int x, int y) {
2898
2899 if (data == null) {
2900 throw new NullPointerException("char data is null");
2901 }
2902 if (offset < 0 || length < 0 || offset + length > data.length) {
2903 throw new ArrayIndexOutOfBoundsException("bad offset/length");
2904 }
2905 if (font.hasLayoutAttributes()) {
2906 if (data.length == 0) {
2907 return;
2908 }
2909 new TextLayout(new String(data, offset, length),
2910 font, getFontRenderContext()).draw(this, x, y);
2911 return;
2912 }
2913
2914 try {
2915 textpipe.drawChars(this, data, offset, length, x, y);
2916 } catch (InvalidPipeException e) {
2917 revalidateAll();
2918 try {
2919 textpipe.drawChars(this, data, offset, length, x, y);
2920 } catch (InvalidPipeException e2) {
2921
2922
2923
2924 }
2925 } finally {
2926 surfaceData.markDirty();
2927 }
2928 }
2929
2930 public void drawBytes(byte data[], int offset, int length, int x, int y) {
2931 if (data == null) {
2932 throw new NullPointerException("byte data is null");
2933 }
2934 if (offset < 0 || length < 0 || offset + length > data.length) {
2935 throw new ArrayIndexOutOfBoundsException("bad offset/length");
2936 }
2937
2938 char chData[] = new char[length];
2939 for (int i = length; i-- > 0; ) {
2940 chData[i] = (char)(data[i+offset] & 0xff);
2941 }
2942 if (font.hasLayoutAttributes()) {
2943 if (data.length == 0) {
2944 return;
2945 }
2946 new TextLayout(new String(chData),
2947 font, getFontRenderContext()).draw(this, x, y);
2948 return;
2949 }
2950
2951 try {
2952 textpipe.drawChars(this, chData, 0, length, x, y);
2953 } catch (InvalidPipeException e) {
2954 revalidateAll();
2955 try {
2956 textpipe.drawChars(this, chData, 0, length, x, y);
2957 } catch (InvalidPipeException e2) {
2958
2959
2960
2961 }
2962 } finally {
2963 surfaceData.markDirty();
2964 }
2965 }
2966
2967
2968
2969
2970
2971
2972 public boolean drawImage(Image img, int x, int y, int width, int height,
2973 ImageObserver observer) {
2974 return drawImage(img, x, y, width, height, null, observer);
2975 }
2976
2977
2978
2979
2980
2981
2982
2983
2984 public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
2985 int width, int height, Color bgcolor,
2986 ImageObserver observer) {
2987 try {
2988 return imagepipe.copyImage(this, img, dx, dy, sx, sy,
2989 width, height, bgcolor, observer);
2990 } catch (InvalidPipeException e) {
2991 revalidateAll();
2992 try {
2993 return imagepipe.copyImage(this, img, dx, dy, sx, sy,
2994 width, height, bgcolor, observer);
2995 } catch (InvalidPipeException e2) {
2996
2997
2998
2999 return false;
3000 }
3001 } finally {
3002 surfaceData.markDirty();
3003 }
3004 }
3005
3006
3007
3008
3009
3010 public boolean drawImage(Image img, int x, int y, int width, int height,
3011 Color bg, ImageObserver observer) {
3012
3013 if (img == null) {
3014 return true;
3015 }
3016
3017 if ((width == 0) || (height == 0)) {
3018 return true;
3019 }
3020 if (width == img.getWidth(null) && height == img.getHeight(null)) {
3021 return copyImage(img, x, y, 0, 0, width, height, bg, observer);
3022 }
3023
3024 try {
3025 return imagepipe.scaleImage(this, img, x, y, width, height,
3026 bg, observer);
3027 } catch (InvalidPipeException e) {
3028 revalidateAll();
3029 try {
3030 return imagepipe.scaleImage(this, img, x, y, width, height,
3031 bg, observer);
3032 } catch (InvalidPipeException e2) {
3033
3034
3035
3036 return false;
3037 }
3038 } finally {
3039 surfaceData.markDirty();
3040 }
3041 }
3042
3043
3044
3045
3046 public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
3047 return drawImage(img, x, y, null, observer);
3048 }
3049
3050
3051
3052
3053
3054 public boolean drawImage(Image img, int x, int y, Color bg,
3055 ImageObserver observer) {
3056
3057 if (img == null) {
3058 return true;
3059 }
3060
3061 try {
3062 return imagepipe.copyImage(this, img, x, y, bg, observer);
3063 } catch (InvalidPipeException e) {
3064 revalidateAll();
3065 try {
3066 return imagepipe.copyImage(this, img, x, y, bg, observer);
3067 } catch (InvalidPipeException e2) {
3068
3069
3070
3071 return false;
3072 }
3073 } finally {
3074 surfaceData.markDirty();
3075 }
3076 }
3077
3078
3079
3080
3081
3082 public boolean drawImage(Image img,
3083 int dx1, int dy1, int dx2, int dy2,
3084 int sx1, int sy1, int sx2, int sy2,
3085 ImageObserver observer) {
3086 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
3087 observer);
3088 }
3089
3090
3091
3092
3093
3094 public boolean drawImage(Image img,
3095 int dx1, int dy1, int dx2, int dy2,
3096 int sx1, int sy1, int sx2, int sy2,
3097 Color bgcolor, ImageObserver observer) {
3098
3099 if (img == null) {
3100 return true;
3101 }
3102
3103 if (dx1 == dx2 || dy1 == dy2 ||
3104 sx1 == sx2 || sy1 == sy2)
3105 {
3106 return true;
3107 }
3108
3109 if (((sx2 - sx1) == (dx2 - dx1)) &&
3110 ((sy2 - sy1) == (dy2 - dy1)))
3111 {
3112
3113 int srcX, srcY, dstX, dstY, width, height;
3114 if (sx2 > sx1) {
3115 width = sx2 - sx1;
3116 srcX = sx1;
3117 dstX = dx1;
3118 } else {
3119 width = sx1 - sx2;
3120 srcX = sx2;
3121 dstX = dx2;
3122 }
3123 if (sy2 > sy1) {
3124 height = sy2-sy1;
3125 srcY = sy1;
3126 dstY = dy1;
3127 } else {
3128 height = sy1-sy2;
3129 srcY = sy2;
3130 dstY = dy2;
3131 }
3132 return copyImage(img, dstX, dstY, srcX, srcY,
3133 width, height, bgcolor, observer);
3134 }
3135
3136 try {
3137 return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2,
3138 sx1, sy1, sx2, sy2, bgcolor,
3139 observer);
3140 } catch (InvalidPipeException e) {
3141 revalidateAll();
3142 try {
3143 return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2,
3144 sx1, sy1, sx2, sy2, bgcolor,
3145 observer);
3146 } catch (InvalidPipeException e2) {
3147
3148
3149
3150 return false;
3151 }
3152 } finally {
3153 surfaceData.markDirty();
3154 }
3155 }
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175 public boolean drawImage(Image img,
3176 AffineTransform xform,
3177 ImageObserver observer) {
3178
3179 if (img == null) {
3180 return true;
3181 }
3182
3183 if (xform == null || xform.isIdentity()) {
3184 return drawImage(img, 0, 0, null, observer);
3185 }
3186
3187 try {
3188 return imagepipe.transformImage(this, img, xform, observer);
3189 } catch (InvalidPipeException e) {
3190 revalidateAll();
3191 try {
3192 return imagepipe.transformImage(this, img, xform, observer);
3193 } catch (InvalidPipeException e2) {
3194
3195
3196
3197 return false;
3198 }
3199 } finally {
3200 surfaceData.markDirty();
3201 }
3202 }
3203
3204 public void drawImage(BufferedImage bImg,
3205 BufferedImageOp op,
3206 int x,
3207 int y) {
3208
3209 if (bImg == null) {
3210 return;
3211 }
3212
3213 try {
3214 imagepipe.transformImage(this, bImg, op, x, y);
3215 } catch (InvalidPipeException e) {
3216 revalidateAll();
3217 try {
3218 imagepipe.transformImage(this, bImg, op, x, y);
3219 } catch (InvalidPipeException e2) {
3220
3221
3222
3223 }
3224 } finally {
3225 surfaceData.markDirty();
3226 }
3227 }
3228
3229
3230
3231
3232
3233 public FontRenderContext getFontRenderContext() {
3234 if (cachedFRC == null) {
3235 int aahint = textAntialiasHint;
3236 if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT &&
3237 antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
3238 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
3239 }
3240
3241 AffineTransform tx = null;
3242 if (transformState >= TRANSFORM_TRANSLATESCALE) {
3243 if (transform.getTranslateX() == 0 &&
3244 transform.getTranslateY() == 0) {
3245 tx = transform;
3246 } else {
3247 tx = new AffineTransform(transform.getScaleX(),
3248 transform.getShearY(),
3249 transform.getShearX(),
3250 transform.getScaleY(),
3251 0, 0);
3252 }
3253 }
3254 cachedFRC = new FontRenderContext(tx,
3255 SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING, aahint),
3256 SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,
3257 fractionalMetricsHint));
3258 }
3259 return cachedFRC;
3260 }
3261 private FontRenderContext cachedFRC;
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272 public void dispose() {
3273 surfaceData = NullSurfaceData.theInstance;
3274 invalidatePipe();
3275 }
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288 public void finalize() {
3289
3290 }
3291
3292
3293
3294
3295
3296
3297 public Object getDestination() {
3298 return surfaceData.getDestination();
3299 }
3300
3301
3302
3303
3304
3305
3306 @Override
3307 public Surface getDestSurface() {
3308 return surfaceData;
3309 }
3310 }